#define  _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>


//1 字符指针变量
 

//int main()
//{//赋首元素首字节地址且放首地址的指针p访问是少了改值功能
//	char* r = "abcdef";//此禁改程度比const深，const修饰的指针少改值但还可以把其地址赋给别的同型指针让别的指针等效替代它指针，因为const禁用不到别指针去改，但它这里是把地址这路都封死了
//	const char* p = "abcdef";//添const非等价单多个那一上层的报错提醒
//	//指针p解引用改值功能是锁的，静的就是该指针不可再对内容改值的静(访问功能还是有，只少了个改值而已)
//	             //'a'
//	printf("%c\n", *p);
//	printf("%s\n", p);//使用%s打印字符串的时候，只需要提供首字符的地址就行
//	*p = 'a';//err
//	*(p + 1) = 'a';//err
//	char* q = p;
//	*q = 'b';
//	printf("%s\n", p);
//	
//	int a = 10;
//	const int* c = &a;
//	*c = 20;//err
//	int* m = c;
//	*m = 20;
//	printf("a=%d\n", a);//const修饰指针就换另一个等价指针禁用不到，就改成功了
//
//	char* n = "abcdef";//没const帮忙警告下
//	*n = 'b';//奔溃(没警告)
//	char* d = p;
//	*d = 'b';//也奔溃，地址这路也彻底封死了(没警告)//它指向的地址始终是只读数据区里的
//
//	const char* g = "abcdef";
//	*g = 'b';//err//加const后这层是帮防到了
//	char* h = g;
//	*h = 'b';//奔溃(没警告)
//	//const没出来指位报错，也没警告拦到指出地奔溃了，没防到
//
//	char arr[] = "abcdef";
//	char* x = arr;//只读数据区里的数据复制放到数组变量里面去，数组变量创建的内存就可对内存里的值修改
//	*x = 'b';//数组可以修改
//	printf("%s\n", arr);//这里的arr也还是首字符地址,能读进地址搜索打印的占位符也就%s
//	printf("%s\n", arr+1);//%s搜索地址对应的字符及后面的全打印
//	printf("%c\n", arr+1);
//	int brr[] = { 1,2,3 };
//	printf("%d\n", brr);//brr也是首元素首字节地址，%d搜索不出来
//	return 0;
//}


//2 常量字符串本身是放在只读数据区里的，它也是块内存，此内存里存放的数据是不可修改的


//int main()
//{
//	char str1[] = "hello bit.";//数组名是此数组变量首元素首字节的地址
//	char str2[] = "hello bit.";//比较的是变量创建空间内存的首字节地址
//	const char* str3 = "hello bit.";//指针变量存地址取存同一个变量里的  //内容相同的常量字符串只需要保存一份就够了
//	const char* str4 = "hello bit.";//比的都是地址，str1、str2本身就是地址，str3、str4是变量，比里面存放的值，也是地址
//	if (str1 == str2)
//		printf("str1 and str2 are same\n");
//	else
//		printf("str1 and str2 are not same\n");
//	if (str3 == str4)
//		printf("str3 and str4 are same\n");
//	else
//		printf("str3 and str4 are not same\n");
//
//	//char a = 0;
//	//char* p = &a;//变量才有创建空间有地址
//	//char* q = &'w';//err
//	//char* b = &10;//err
//	return 0;
//}


//3 数组指针变量
// 创建指针变量时右边都会赋首字节地址，要全访问到该变量就用该变量类型加个*的指针类型表示会访问到此变量大小的地址访问量，效果是要访问到int类型那么多，即指针指向对象，指针类型里的变量类型表示宽度会访问到此变量类型内存大小，指针类型里的变量类型即指针指向对象
// 创建变量时
//名称去掉是类型
//指针去名(指针类型)再去*是指针指向对象，即此指针创建来存放地址的对象变量类型


//int main()
//{
//	int arr[10] = { 1,2,3,4,5 };//一个创建的变量把名字去掉就是类型，类型+名字创建的变量
//	int* q[10];//int与*结合，q与[10]结合成整型指针数组，把q去掉int*[10]就是这个数组的类型 -- int* [10]
//	int a[10] = { 0 };//数组算是个变量，小变量组成的大变量
//	//数组也是有类型，类型[个数] -- int [10]
////数组指针变量的p要与*用()结合起来表指针，防止p与[]结合成数组
//	int(*p)[10] = &arr;//数组指针，p与前面的*结合是指针，int[10]类型表明指向10个元素的整型数组类型，int(*)[10]就是指向10个int的指针类型，p就是数组指针,p中存放的是数组的地址
//	//&arr -- int(*)[10]类型，形式还是存头字节地址控10个元素地址
//	int *ptr;//ptr与前面的*结合是指针，int表明指针指向整型，指向整型的指针
//	
//	char* ch[5];
//	    //指针接值 //其实也是首元素地址传过来
//	char* (*pc)[5] = &ch;
////访问各宽度//访问宽度×    //因为数组是连续的
//	//数组指针为每个元素地址放
//
//	char ah[5];
//	char(*pa)[5] = &ah;
//	return 0;
//}


//4


//int main()
//{
//	int a = 10;
//	int* q = &a;//指针变量q相当于&a
//	*q;// <==> *&a == a
//	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
//	int(*p)[10] = &arr;//取出的是数组的地址
//	int i = 0;
//	//使用p这个数组指针访问arr数组的内容
//	for (i = 0;i < 10;i++)
//	{               //*&arr
//		printf("%d ", (*p)[i]);
//	}               //arr
//	printf("\n");
//	int* b = arr;
//	for (i = 0;i < 10;i++)
//	{
//		printf("%d ", b[i]);
//	}
//	return 0;
//}


//5 


////void Print(int arr[3][5], int r, int c)
////{
////	int i = 0;
////	for (i = 0;i < r;i++)
////	{
////		int j = 0;
////		for (j = 0;j < c;j++)
////		{
////			printf("%d ", arr[i][j]);
////		}
////		printf("\n");
////	}
////}
//
//void Print(int (*p)[5], int r, int c)
//{
//	int i = 0;
//	for (i = 0;i < r;i++)
//	{
//		int j = 0;
//		for (j = 0;j < c;j++)//二维数组arr[i][j]里的arr[i]从*(arr+i)是元素数组内容变成&arr[i][0]了，被取代掉了，成每个元素数组首元素地址了
//		{//二维数组里元素数组的总内容是此元素数组的数组名
//			printf("%d ",(*(p+i))[j]);// <==> *((*(p+i))+j)
//		}
//		printf("\n");
//	}
//}
//int main()
//{
//	int arr[3][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7} };//二维数组是一维数组的数组
//	Print(arr,3,5);
//	//也是传数组首元素的地址，首元素是一个数组
//	//二维数组的数组名就是它第一行的地址
//	return 0;
//}


//6 函数指针变量


//int Add(int x, int y)
//{
//	return x + y;
//}
//int main()
//{
//	int x = 0;
//	int y = 0;
//	Add(x, y);//&函数名和函数名都是函数的地址，没有区别
//	printf("%p\n", Add);
//	printf("%p\n", &Add);
//	int(*p)(int, int) = &Add;//p --> 函数指针变量
////函数指针变量的p与*也要用()结合起来，因为p后面有括号，不把p与*用()结合起来表指针的话p会与后面的()结合成函数
//	int (*q)(int x, int y) = &Add;//x,y加不加都行，没有意义的;*也是摆设，多少颗*都可以
//      //函数指针变量右边这里需要括号的
//	//相当于一次函数调用
//	int ret = (*p)(3, 5);
//	  //函数所有功能信息
//	printf("%d\n", ret);
//
//	//函数直接地址也行
//	int aet = Add(3, 5);
//	printf("%d\n", aet);
//	int bet = p(3, 5);
//	printf("%d\n", bet);
//	return 0;
//}


//7


//void a(int x)
//{
//	return (x );
//}
////是一次函数调用
//int main()
//{
//	(*((void(*)())0))();
//	return 0;
//}
//
////一次函数声明
//typedef void(*gf_t)(int);
//int main()
//{
//	void(*singal(int, void(*)(int)))(int);
//	//void(*)(int) singal (int,void(*)(int));
//	gf_t singal2(int, gf_t);
//	return 0;
//}


//8 typedef类型名称自定义，给类型起了别名
//新的类型名字放到原本变量名字那边定义


//typedef unsigned int  uint;
//typedef int* pint_t;
//typedef int(*parrt)[6];//数组指针重命名
//typedef int(*pf_t)(int, int);//函数指针类型重命名
//int Add(int x, int y)
//{
//	return x + y;
//}
//int main()
//{
//	
//	unsigned num;
//	uint unm2;
//	int* p;
//	pint_t p2;
//	int arr[6] = { 0 };
//	int(*q)[6] = &arr;
//	parrt q2 = &arr;
//	int(*a)(int, int) = Add;
//	pf_t b = Add;
//	return 0;
//}


//9 函数指针数组


//int Add(int x, int y)
//{
//	return x + y;
//}
//int Sub(int x, int y)
//{
//	return x - y;
//}
//int Mul(int x, int y)
//{
//	return x * y;
//}
//int Div(int x, int y)
//{
//	return x / y;
//}
//int main()
//{//int(*)(int,int) 数组变量把名称与[]去掉即里面每个元素的类型
//	int(*p[4])(int, int) = { Add,Sub,Mul,Div };
//	int i = 0;
//	for (i = 0;i < 4;i++)
//	{
//		int ret = p[i](6, 2);
//		printf("%d\n", ret);
//	}
//	return 0;
//}


//10 计算器


//////switch来写
////int Add(int x, int y)
////{
////	return x + y;
////}
////int Sub(int x, int y)
////{
////	return x - y;
////}
////int Mul(int x, int y)
////{
////	return x * y;
////}
////int Div(int x, int y)
////{
////	return x / y;
////}
////void menu()
////{
////	printf("******************************************************\n");
////	printf("********************1.Add  2.Sub**********************\n");
////	printf("********************3.Mul  4.Div**********************\n");
////	printf("*********************** 0.exit ***********************\n");
////
////}
////int x = 0;
////int y = 0;
////int ret = 0;
////int main()
////{
////	int a = 0;
////	do
////	{
////		menu();
////		printf("请选择:\n");
////		scanf("%d", &a);
////		switch (a)
////		{
////		printf("hehe\n"); //跳着进的，读不到这
////		case 1:
////			printf("请输入两个数\n");
////			scanf("%d %d", &x, &y);
////			ret = Add(x, y);
////			printf("%d\n", ret);
////			break;
////		case 2:
////			printf("请输入两个数\n");
////			scanf("%d %d", &x, &y);
////			ret = Sub(x, y);
////			printf("%d\n", ret);
////			break;
////		case 3:
////			printf("请输入两个数\n");
////			scanf("%d %d", &x, &y);
////			ret = Mul(x, y);
////			printf("%d\n", ret);
////			break;
////		case 4:
////			printf("请输入两个数\n");
////			scanf("%d %d", &x, &y);
////			ret = Div(x, y);
////			printf("%d\n", ret);
////			break;
////		case 0:
////			printf("已退出计算器\n");
////			break;
////		default:
////			printf("输入错误，请重新选择\n");
////			break;
////		}
////	}
////	while (a);
////	return 0;
////}
//
//
////函数指针数组来写
//int Add(int x, int y)
//{
//	return x + y;
//}
//int Sub(int x, int y)
//{
//	return x - y;
//}
//int Mul(int x, int y)
//{
//	return x * y;
//}
//int Div(int x, int y)
//{
//	return x / y;
//}
//void menu()
//{
//	printf("******************************************************\n");
//	printf("********************1.Add  2.Sub**********************\n");
//	printf("********************3.Mul  4.Div**********************\n");
//	printf("*********************** 0.exit ***********************\n");
//
//}
//int x = 0;
//int y = 0;
//int ret = 0;
//int main()
//{
//	int a = 0;
//	do
//	{
//		menu();
//		printf("请选择:\n");
//		scanf("%d", &a);
//		//函数指针数组 -- 转移表
//		int(*pf[5])(int, int) = { 0,Add,Sub,Mul,Div };
//		if (a >= 1 && a <= 4)
//		{
//			printf("请输入两个数:\n");
//			scanf("%d %d", &x, &y);
//			ret = pf[a](x, y);
//			printf("%d\n", ret);
//		}
//		else if (a == 0)
//			printf("已退出计算器\n");
//		else
//			printf("输入错误，请重新选择\n");
//	} while (a);
//	return 0;
//}
//
//
////回调函数来写
//void menu()
//{
//	printf("******************************************************\n");
//	printf("********************1.Add  2.Sub**********************\n");
//	printf("********************3.Mul  4.Div**********************\n");
//	printf("*********************** 0.exit ***********************\n");
//}
//int Add(int x, int y)
//{
//	return x + y;
//}
//int Sub(int x, int y)
//{
//	return x - y;
//}
//int Mul(int x, int y)
//{
//	return x * y;
//}
//int Div(int x, int y)
//{
//	return x / y;
//}
//void Calc(int(*p)(int, int))
//{
//	int ret = 0;
//	int x = 0;
//	int y = 0;
//	printf("请输入两个数:\n");
//	scanf("%d %d", &x, &y);
//	ret = p(x, y);
//	printf("%d\n", ret);
//}
//int main()
//{
//	int a = 0;
//	do
//	{
//		menu();
//		printf("请选择:\n");
//		scanf("%d", &a);
//		switch (a)
//		{
//		case 1:
//			Calc(Add);
//			break;
//		case 2:
//			Calc(Sub);
//			break;
//		case 3:
//			Calc(Mul);
//			break;
//		case 4:
//			Calc(Div);
//			break;
//		case 0:
//			printf("已退出计算器\n");
//			break;
//		default:
//			printf("输入错误，请重新选择\n");
//		}
//	} while (a);
//	return 0;
//}